package com.lxu.report.service;

import com.lxu.report.entity.YwReportData;
import com.lxu.report.entity.bo.ReportDirBO;
import com.lxu.report.entity.bo.ReportTableBO;
import com.lxu.report.util.ReportExceptionUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * word报表工具 服务类
 */
@Service
public class WordTemplateService {

    @Autowired
    private TemplateQueryService templateQueryService;

    @Autowired
    private WordTemplateFillService wordTemplateFillService;

    @Autowired
    private TemplateDataAssembleService templateDataAssembleService;

    @Autowired
    private WordCombineService wordCombineService;

    @Resource
    private ReportFileOperationService reportFileOperationService;

    @Resource
    private TemplateNameAssembleService templateNameAssembleService;

    @Resource
    private MultipleTableCopyService multipleTableCopyService;

    /**
     * 按照数据库预置模板顺序，填充模板数据，并合并
     * <p>
     * 1、根据模板编号，拉取报告模板目录，并复制到客户对应的报告表中;
     * 2、获取模板配置对应的数据，形成最终的数据模型；
     * 3、填充拉取的报告模板；
     * 4、合并报告模板；
     *
     * @param ywReportData 实际 报表模板
     */
    @Transactional
    public String exportWordTemplate(OutputStream out, YwReportData ywReportData) throws Exception {

        ywReportData = templateQueryService.queryReportTemplate(ywReportData);

        if (ywReportData == null) {
            throw new RuntimeException(ReportExceptionUtil.TEMPLATE_IS_NULL);
        }
        /**
         * 2、获取模板配置对应的数据，形成最终的数据模型；
         */
        List<ReportDirBO> dirs = templateQueryService.queryReportDirs(ywReportData);
        if (CollectionUtils.isEmpty(dirs)) {
            throw new RuntimeException(ReportExceptionUtil.DIR_IS_NULL);
        }
        /**
         * 处理尽职调查-关联方信息，这种特殊情况
         * 表格里面嵌套扩展行，表格需要进行复制，嵌套扩展行也需要扩展
         */
        if(multipleTableCopyService.init(ywReportData,dirs)){
             dirs = templateQueryService.queryReportDirs(ywReportData);
        }

        /**
         * 3、初始化模板目录生成路径和最终报告的生成路径
         */
        initTemplateFilePath(ywReportData, dirs);
        /**
         *4、核心功能-模板组装及数据组装
         */
        for (ReportDirBO dir : dirs) {
            Map<String, Object> templateTextMap = new HashMap<>();
            Map<String, List<List<String>>> templateTableMap = new HashMap<>();
            List<ReportTableBO> templateTables = new ArrayList<>();

            /**
             * 4.1、调用模板数据组装接口
             */
            templateDataAssembleService.generateTemplateData(dir, templateTextMap, templateTableMap, templateTables);

            /**
             * 4.2、调用数据填充接口
             */
            wordTemplateFillService.fill(dir, templateTextMap, templateTables);
        }

        /**
         * 5、组装填充后的模板
         */
        List<File> srcfiles = new ArrayList<File>();
        for (ReportDirBO dir : dirs) {
            srcfiles.add(new File(dir.getDestFilePath()));
        }
        /**
         * 6、创建目录
         */
        File file = new File(ywReportData.getReportAddr());
        if(!file.exists()){
            file.mkdirs();
        }
        //String fileName = ywReportData.getTemplateTypeCode()+"_"+ywReportData.getExportRecordId()+"_"+System.nanoTime();
        String fileName = templateNameAssembleService.assembleTemplateName(ywReportData);
        String absoluteFile = assembleReportFile(ywReportData.getReportAddr(),fileName);

        /**
         * 7、更新文件及数据库记录
         */
        reportFileOperationService.refreshFileAndDB(absoluteFile,ywReportData,true);

        /**
         * 8、合并文件
         */
        wordCombineService.combine(absoluteFile, srcfiles);

        /**
         * 9、删除过程中的临时文件
         */
        reportFileOperationService.deleteSrcfiles(srcfiles);

        /**
         *10、导出
         */
        if(out !=null){
            file = new File(absoluteFile);
            InputStream inputStream = new FileInputStream(file);
            new XWPFDocument(inputStream).write(out);
        }
        return absoluteFile;
    }

    /**
     * 根据数据库的路径获取到文件读取的绝对路径
     *
     * @param ywReportData
     * @param dirs
     */
    private void initTemplateFilePath(YwReportData ywReportData, List<ReportDirBO> dirs) {
        String basePath = "e:\\\\files\\\\";
        for (ReportDirBO dir : dirs) {
            String templateFilePath = dir.getTemplateFilePath();
            if (StringUtils.isNotBlank(templateFilePath)) {
                String relative = templateFilePath.substring(9, templateFilePath.length() - 3);
                dir.setTemplateFilePath(basePath + relative);
                dir.setDestFilePath(basePath + relative.substring(0, relative.length() - 5) + "-temp" + relative.substring(relative.length() - 5, relative.length()));
            }
        }
        ywReportData.setReportAddr(assembleReportAddr(basePath));
    }

    /**
     * 组装最终导出文件生成路径
     * @return
     */
    private String assembleReportAddr(String basePath) {
        String reportWord ="userfiles\\\\report_word";
        StringBuffer sb = new StringBuffer();
        return sb.append(basePath)
                 .append(File.separator)
                 .append(reportWord)
                 .append(File.separator)
                 .append(LocalDate.now().getYear())
                 .append(File.separator)
                 .append(LocalDate.now().getMonthValue())
                 .append(File.separator)
                 .append(LocalDate.now().getDayOfMonth())
                 .toString();
    }

    /**
     * 组装最终导出文件生成名称
     * @param path
     * @return
     */
    private String assembleReportFile(String path,String fileName){
        StringBuffer sb = new StringBuffer();
        return sb.append(path)
          .append(File.separator)
          .append(fileName)
          .append(".docx")
          .toString();
    }
}
